using System;
using System.Collections.Generic;
using System.Text;
using System.Xml;
using Stratman.Utilities;
using RedGate.SQLCompare.Engine;

namespace Stratman.DesktopProcess.DatabaseSynchronizer
{
    /// <summary>
    /// Collects information regarding the synchronization process, including connection 
    /// information for the source and target databases, objects to include in the synchronization
    /// process, and tables whose data we should generate scripts for.
    /// </summary>
    public class SynchronizationOptions
    {
        /// <summary>
        /// The server name of the source database.
        /// </summary>
        protected string sourceServerName = "";
        /// <summary>
        /// The database name of the source database.
        /// </summary>
        protected string sourceDatabase = "";
        /// <summary>
        /// The username that we should use when connecting to the source database (leave this and
        /// the source password blank to connect using Windows authentication).
        /// </summary>
        protected string sourceUserName = "";
        /// <summary>
        /// The password that we should use when connecting to the source database (leave this and
        /// the source username blank to connect using Windows authentication).
        /// </summary>
        protected string sourcePassword = "";
        /// <summary>
        /// The server name of the target database.
        /// </summary>
        protected string targetServerName = "";
        /// <summary>
        /// The database name of the target database.
        /// </summary>
        protected string targetDatabase = "";
        /// <summary>
        /// The username that we should use when connecting to the target database (leave this and
        /// the target password blank to connect using Windows authentication).
        /// </summary>
        protected string targetUserName = "";
        /// <summary>
        /// The password that we should use when connecting to the target database (leave this and
        /// the target username blank to connect using Windows authentication).
        /// </summary>
        protected string targetPassword = "";
        /// <summary>
        /// A list of object type -> bool mappings indicating the object types for which we should
        /// synchronize all object instances.
        /// </summary>
        Dictionary<ObjectType, bool> processAllOfObjectType = new Dictionary<ObjectType, bool>();
        /// <summary>
        /// If an object type is not having all of its object instances processed, this contains
        /// the list of objects, by type, that we should include during synchronization.
        /// </summary>
        Dictionary<ObjectType, List<string>> includedObjects = new Dictionary<ObjectType, List<string>>(); 
        /// <summary>
        /// A list of tables for which we should generate data-insertion scripts.
        /// </summary>
        List<string> staticTables = new List<string>();

        /// <summary>
        /// Sets the indicator for whether or not we're synchronizing all objects of a particular
        /// type for each object type.
        /// </summary>
        /// <param name="value">
        /// Value that we should set the flag to.
        /// </param>
        public void SetAllObjectTypes(bool value)
        {
            processAllOfObjectType.Clear();

            foreach (int objectType in Enum.GetValues(typeof(ObjectType)))
                processAllOfObjectType.Add((ObjectType)objectType, value);
        }

        /// <summary>
        /// Loads settings from a project file, including the source and target database connection
        /// information and the list of objects and static tables to process.
        /// </summary>
        /// <param name="projectFilePath">
        /// Project file from which we are to load our settings.
        /// </param>
        public void Load(string projectFilePath)
        {
            XmlDocument project = new XmlDocument();
            project.Load(projectFilePath);

            // Get the source and target database connection information
            sourceServerName = XmlUtilities.GetSafeXmlValue(project, "/SynchronizerProject/Source/ServerName", "");
            sourceDatabase = XmlUtilities.GetSafeXmlValue(project, "/SynchronizerProject/Source/Database", "");
            sourceUserName = XmlUtilities.GetSafeXmlValue(project, "/SynchronizerProject/Source/UserName", "");
            sourcePassword = XmlUtilities.GetSafeXmlValue(project, "/SynchronizerProject/Source/Password", "");
            targetServerName = XmlUtilities.GetSafeXmlValue(project, "/SynchronizerProject/Target/ServerName", "");
            targetDatabase = XmlUtilities.GetSafeXmlValue(project, "/SynchronizerProject/Target/Database", "");
            targetUserName = XmlUtilities.GetSafeXmlValue(project, "/SynchronizerProject/Target/UserName", "");
            targetPassword = XmlUtilities.GetSafeXmlValue(project, "/SynchronizerProject/Target/Password", "");

            processAllOfObjectType.Clear();
            includedObjects.Clear();
            staticTables.Clear();

            // Get the list of objects that we are to process
            foreach (string objectType in Enum.GetNames(typeof(ObjectType)))
            {
                processAllOfObjectType[(ObjectType)Enum.Parse(typeof(ObjectType), objectType)] = Convert.ToBoolean(XmlUtilities.GetSafeXmlValue(project, "/SynchronizerProject/" + StringUtilities.Pluralize(objectType) + "/@All", "false"));
                includedObjects[(ObjectType)Enum.Parse(typeof(ObjectType), objectType)] = new List<string>();
                FillList(includedObjects[(ObjectType)Enum.Parse(typeof(ObjectType), objectType)], project.SelectNodes("/SynchronizerProject/" + StringUtilities.Pluralize(objectType) + "/" + objectType));
            }

            // Get the list of static tables that we are to process
            FillList(staticTables, project.SelectNodes("/SynchronizerProject/StaticTables/StaticTable"));
        }

        /// <summary>
        /// A list of tables for which we should generate data-insertion scripts.
        /// </summary>
        public List<string> StaticTables
        {
            get 
            { 
                return staticTables; 
            }
            
            set 
            { 
                staticTables = value; 
            }
        }

        /// <summary>
        /// The password that we should use when connecting to the target database (leave this and
        /// the target username blank to connect using Windows authentication).
        /// </summary>
        public string TargetPassword
        {
            get 
            { 
                return targetPassword; 
            }

            set 
            { 
                targetPassword = value; 
            }
        }

        /// <summary>
        /// The password that we should use when connecting to the target database (leave this and
        /// the target username blank to connect using Windows authentication).
        /// </summary>
        public string TargetUserName
        {
            get 
            { 
                return targetUserName; 
            }
            
            set 
            { 
                targetUserName = value; 
            }
        }

        /// <summary>
        /// The username that we should use when connecting to the target database (leave this and
        /// the target password blank to connect using Windows authentication).
        /// </summary>
        public string TargetDatabase
        {
            get 
            { 
                return targetDatabase; 
            }
            
            set 
            { 
                targetDatabase = value; 
            }
        }

        /// <summary>
        /// The server name of the target database.
        /// </summary>
        public string TargetServerName
        {
            get 
            { 
                return targetServerName; 
            }

            set 
            { 
                targetServerName = value; 
            }
        }

        /// <summary>
        /// The password that we should use when connecting to the source database (leave this and
        /// the source username blank to connect using Windows authentication).
        /// </summary>
        public string SourcePassword
        {
            get 
            { 
                return sourcePassword; 
            }
            
            set 
            { 
                sourcePassword = value; 
            }
        }

        /// <summary>
        /// The username that we should use when connecting to the source database (leave this and
        /// the source password blank to connect using Windows authentication).
        /// </summary>
        public string SourceUserName
        {
            get 
            { 
                return sourceUserName; 
            }
            
            set 
            { 
                sourceUserName = value; 
            }
        }

        /// <summary>
        /// The database name of the source database.
        /// </summary>
        public string SourceDatabase
        {
            get 
            { 
                return sourceDatabase; 
            }
            
            set 
            { 
                sourceDatabase = value; 
            }
        }

        /// <summary>
        /// The server name of the source database.
        /// </summary>
        public string SourceServerName
        {
            get 
            { 
                return sourceServerName; 
            }
            
            set 
            { 
                sourceServerName = value; 
            }
        }

        /// <summary>
        /// A list of object type -> bool mappings indicating the object types for which we should
        /// synchronize all object instances.
        /// </summary>
        public Dictionary<ObjectType, bool> ProcessAllOfObjectType
        {
            get
            {
                return processAllOfObjectType;
            }
        }

        /// <summary>
        /// If an object type is not having all of its object instances processed, this contains
        /// the list of objects, by type, that we should include during synchronization.
        /// </summary>
        public Dictionary<ObjectType, List<string>> IncludedObjects
        {
            get
            {
                return includedObjects;
            }
        }

        /// <summary>
        /// Fill a string List instance with values from a list of XML nodes.
        /// </summary>
        /// <param name="list">
        /// List that we are to fill.
        /// </param>
        /// <param name="nodes">
        /// List of XML nodes from which we are to get our values.
        /// </param>
        protected void FillList(List<string> list, XmlNodeList nodes)
        {
            list.Clear();

            foreach (XmlNode node in nodes)
                list.Add(node.InnerText);
        }
    }
}
